<template>
  <div class="fund-data-hub-wrapper">
    <div class="fund-data-hub">
    <el-card class="header-card">
      <div class="title">
        <el-icon class="title-icon"><DataAnalysis /></el-icon>
        <span class="title-text">Fund Data Hub</span>
        <span class="title-divider">｜</span>
        <span class="title-subtitle">基金数据更新中心</span>
      </div>
      <div class="account-bar">
        <el-form :inline="true" :model="account" label-width="80px" class="account-form">
          <el-form-item label="账号">
            <el-input v-model="account.username" placeholder="聚宽账户" clearable>
              <template #prefix>
                <el-icon><User /></el-icon>
              </template>
            </el-input>
          </el-form-item>
          <el-form-item label="密码">
            <el-input v-model="account.password" type="password" show-password placeholder="聚宽密码">
              <template #prefix>
                <el-icon><Lock /></el-icon>
              </template>
            </el-input>
          </el-form-item>
          <el-form-item>
            <el-checkbox v-model="remember">记住账号</el-checkbox>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="saveAccountIfNeeded" round>
              <el-icon><Check /></el-icon>
              保存
            </el-button>
          </el-form-item>
        </el-form>
        <el-alert type="info" :closable="false" show-icon class="account-alert">
          <template #title>
            <span class="tips">日期权限提示：账号仅可访问当前日期前 <b>15 个月</b>至 <b>3 个月</b>的数据，超出部分将自动调整。</span>
          </template>
        </el-alert>
        <div class="account-tip-card">
          <el-icon class="tip-icon-account"><InfoFilled /></el-icon>
          <div class="tip-content-account">
            <div class="tip-title-account">💡 使用提示</div>
            <ul class="tip-list-account">
              <li>账号信息会安全保存在本地浏览器，下次访问时自动填充</li>
              <li>建议使用具有完整数据访问权限的正式账号，确保数据更新的完整性</li>
              <li>如遇到权限问题，请检查账号的数据访问范围或联系系统管理员</li>
            </ul>
          </div>
        </div>
      </div>
    </el-card>

    <el-card class="main-card">
      <el-tabs v-model="activeTab" type="card">
        <el-tab-pane label="预设更新计划" name="preset">
          <div class="preset-tab-content">
            <!-- 预设计划卡片区域 -->
            <div class="plan-section">
              <h3 class="section-title-main">预设更新计划</h3>
              <div class="plan-grid">
                <el-card v-for="p in plans" :key="p.planCode" class="plan-card" :class="{selected: selectedPlan && selectedPlan.planCode===p.planCode}" @click="selectedPlan=p">
                  <div class="plan-title">
                    <el-tag type="info">{{ p.planCode }}</el-tag>
                    <span class="plan-name">{{ p.brief }}</span>
                  </div>
                  <div class="plan-meta">
                    <div><b>数据类型：</b>{{ mapPlanTypes(p.dataTypes) }}</div>
                    <div><b>策略：</b>{{ modeLabel[p.mode] }} + {{ strategyLabel[p.strategy] }}</div>
                    <div><b>时间窗口：</b>{{ p.window }}</div>
                    <div class="hint">{{ p.tip }}</div>
                  </div>
                </el-card>
              </div>

              <el-form :model="presetForm" label-width="120px" class="preset-form">
                <el-form-item label="基金范围">
                  <el-input v-model="presetForm.fundCodesRaw" type="textarea" :rows="3" placeholder="可选，留空则全库基金" />
                </el-form-item>
                <el-form-item>
                  <el-button type="primary" :disabled="!selectedPlan" :loading="running" @click="runPlan">执行计划</el-button>
                  <span class="preset-tips">预设计划适用于常规巡检，需要快速执行固定策略时使用。如需改变 dataTypes 或窗口，请切换到"自定义"模式。</span>
                </el-form-item>
              </el-form>
            </div>

            <!-- 公告和持仓更新区域 -->
            <div class="announcement-holding-section">
              <h3 class="section-title-main">公告与持仓更新</h3>
              <el-card class="announcement-holding-card">
                <div class="announcement-holding-container">
                  <!-- 基金公告更新区域 -->
                  <div class="update-section announcement-section">
                    <div class="section-header">
                      <div class="section-title">
                        <el-icon class="section-icon"><Document /></el-icon>
                        <span class="section-name">基金公告更新</span>
                      </div>
                      <el-switch 
                        v-model="announcementHoldingForm.enableAnnouncement" 
                        active-text="启用"
                        inactive-text="禁用"
                        size="default"
                      />
                    </div>
                    <div v-if="announcementHoldingForm.enableAnnouncement" class="section-content">
                      <div class="mode-selector">
                        <div 
                          v-for="mode in announcementModes" 
                          :key="mode.value"
                          class="mode-option"
                          :class="{ active: announcementHoldingForm.announcementMode === mode.value }"
                          @click="announcementHoldingForm.announcementMode = mode.value"
                        >
                          <el-icon class="mode-icon">
                            <FullScreen v-if="mode.icon === 'FullScreen'" />
                            <Clock v-else-if="mode.icon === 'Clock'" />
                            <Warning v-else-if="mode.icon === 'Warning'" />
                            <Delete v-else-if="mode.icon === 'Delete'" />
                          </el-icon>
                          <span class="mode-label">{{ mode.label }}</span>
                          <span class="mode-desc">{{ mode.desc }}</span>
                        </div>
                      </div>
                    </div>
                  </div>

                  <!-- 基金持仓更新区域 -->
                  <div class="update-section holding-section">
                    <div class="section-header">
                      <div class="section-title">
                        <el-icon class="section-icon"><TrendCharts /></el-icon>
                        <span class="section-name">基金持仓更新</span>
                      </div>
                      <el-switch 
                        v-model="announcementHoldingForm.enableHolding" 
                        active-text="启用"
                        inactive-text="禁用"
                        size="default"
                      />
                    </div>
                    <div v-if="announcementHoldingForm.enableHolding" class="section-content">
                      <div class="mode-selector">
                        <div 
                          v-for="mode in holdingModes" 
                          :key="mode.value"
                          class="mode-option"
                          :class="{ active: announcementHoldingForm.holdingMode === mode.value }"
                          @click="announcementHoldingForm.holdingMode = mode.value"
                        >
                          <el-icon class="mode-icon">
                            <Clock v-if="mode.icon === 'Clock'" />
                            <Delete v-else-if="mode.icon === 'Delete'" />
                          </el-icon>
                          <span class="mode-label">{{ mode.label }}</span>
                          <span class="mode-desc">{{ mode.desc }}</span>
                        </div>
                      </div>
                      <!-- 年份选择器（仅在年份模式时显示） -->
                      <div v-if="announcementHoldingForm.holdingMode === 'year'" class="year-selector">
                        <el-form-item label="指定年份" label-width="100px">
                          <el-input-number 
                            v-model="announcementHoldingForm.holdingYear" 
                            :min="2000" 
                            :max="new Date().getFullYear()" 
                            placeholder="选择年份" 
                            style="width: 100%;"
                            controls-position="right"
                          />
                        </el-form-item>
                      </div>
                    </div>
                  </div>
                </div>
              </el-card>

              <!-- 共用按钮区域 -->
              <div class="shared-actions">
                <el-button type="primary" :loading="running" @click="runAnnouncementHolding">执行更新</el-button>
                <el-button @click="resetAnnouncementHolding">重置选项</el-button>
              </div>
            </div>
          </div>
        </el-tab-pane>

        <el-tab-pane label="自定义更新策略" name="advanced">
          <div class="tab-wrap">
            <el-form :model="advancedForm" label-width="120px" class="advanced-form">
              <el-form-item label="基金范围">
                <el-input
                  v-model="advancedForm.fundCodesRaw"
                  type="textarea"
                  :rows="3"
                  placeholder="逗号或换行分隔，不填代表所有基金"
                />
              </el-form-item>

              <el-form-item label="数据类型">
                <el-checkbox-group v-model="advancedForm.dataTypes">
                  <el-checkbox v-for="opt in DATA_TYPE_OPTS" :key="opt.value" :label="opt.value">{{ opt.label }}</el-checkbox>
                </el-checkbox-group>
              </el-form-item>

              <div class="form-inline-2">
                <el-form-item label="更新模式">
                  <el-select v-model="advancedForm.mode" placeholder="选择模式" style="width: 260px;">
                    <el-option label="自动更新" value="AUTO_UPDATE" />
                    <el-option label="手动更新" value="MANUAL_UPDATE" />
                  </el-select>
                </el-form-item>
                <el-form-item label="更新策略">
                  <el-select v-model="advancedForm.strategy" placeholder="选择策略" style="width: 260px;">
                    <el-option label="增量" value="INCREMENTAL" />
                    <el-option label="全量区间" value="FULL_RANGE" />
                    <el-option label="最近天数" value="RECENT_DAYS" />
                  </el-select>
                </el-form-item>
              </div>

              <template v-if="advancedForm.strategy === 'INCREMENTAL' || advancedForm.strategy === 'FULL_RANGE'">
                <el-form-item label="时间范围">
                  <el-date-picker v-model="dateRange" type="daterange" unlink-panels start-placeholder="开始日期" end-placeholder="结束日期" style="width: 420px;" />
                </el-form-item>
              </template>
              <template v-else>
                <el-form-item label="最近天数">
                  <el-input-number v-model="advancedForm.recentDays" :min="1" :max="365" />
                </el-form-item>
              </template>

              <div class="form-inline-2">
                <el-form-item label="并发执行">
                  <el-switch v-model="advancedForm.concurrent" />
                </el-form-item>
                <el-form-item label="删除旧数据">
                  <el-switch v-model="advancedForm.deleteOldBeforeInsert" />
                </el-form-item>
              </div>

              <el-form-item>
                <el-button type="primary" :loading="running" @click="runAdvanced">执行更新</el-button>
                <el-button @click="resetAdvanced">重置选项</el-button>
              </el-form-item>
            </el-form>
          </div>
        </el-tab-pane>

        <el-tab-pane label="自动更新说明" name="automation">
          <div class="auto-wrap">
            <div class="auto-status">
              <div class="auto-overview" :class="{ compact: compactMode }">
                <div class="overview-header">
                  <div class="header-left">
                    <h3>自动更新策略概览</h3>
                    <p>为了让常用数据自动保持最新，系统采用内置计划：</p>
                  </div>
                  <div class="overview-tools">
                    <el-switch v-model="compactMode" active-text="紧凑模式" />
                  </div>
                </div>

                <div class="overview-grid">
                  <div class="overview-card">
                    <div class="card-head head-blue">
                      <div class="icon-circle icon-blue"><el-icon><TrendCharts /></el-icon></div>
                      <span class="badge badge-blue">Daily Market</span>
                      <span class="sub">每日行情</span>
                    </div>
                    <ul class="card-list">
                      <li><label>内容</label><span>净值、货基收益、融资融券</span></li>
                      <li><label>频率</label><span>每日凌晨/盘后</span></li>
                      <li><label>方式</label><span>增量更新最近 7 天</span></li>
                      <li><label>适用</label><span>日常维持行情类数据的实时性</span></li>
                    </ul>
                    <details class="card-actions">
                      <summary>展开更多说明</summary>
                      <div class="card-more">
                        建议：日常固定在盘后运行。如需手动触发，可使用下方“立即执行 daily-market 计划后者使用预设更新计划，选择对应策略进行更新”。
                      </div>
                    </details>
                  </div>

                  <div class="overview-card">
                    <div class="card-head head-green">
                      <div class="icon-circle icon-green"><el-icon><Histogram /></el-icon></div>
                      <span class="badge badge-green">Weekly Leverage</span>
                      <span class="sub">周度杠杆</span>
                    </div>
                    <ul class="card-list">
                      <li><label>内容</label><span>融资融券数据</span></li>
                      <li><label>频率</label><span>每周一凌晨</span></li>
                      <li><label>方式</label><span>增量更新最近 14 天</span></li>
                      <li><label>适用</label><span>需要周度趋势或补充长窗口杠杆数据的场景</span></li>
                    </ul>
                    <details class="card-actions">
                      <summary>展开更多说明</summary>
                      <div class="card-more">
                        提示：如需停用，请联系系统管理员在application.properties 中清空对应 cron；或在后端关闭该计划。
                      </div>
                    </details>
                  </div>

                  <div class="overview-card">
                    <div class="card-head head-orange">
                      <div class="icon-circle icon-orange"><el-icon><Document /></el-icon></div>
                      <span class="badge badge-orange">Monthly Financial</span>
                      <span class="sub">月度财务</span>
                    </div>
                    <ul class="card-list">
                      <li><label>内容</label><span>基金财务指标（季报/半年报等）</span></li>
                      <li><label>频率</label><span>每月 1 日</span></li>
                      <li><label>方式</label><span>增量更新最近一个季度</span></li>
                      <li><label>适用</label><span>季报发布后及时补齐财务指标</span></li>
                    </ul>
                    <details class="card-actions">
                      <summary>展开更多说明</summary>
                      <div class="card-more">
                        建议：与季报披露节奏配合运行；必要时可配合“季度复核”计划确保完整性。
                      </div>
                    </details>
                  </div>

                  <div class="overview-card">
                    <div class="card-head head-purple">
                      <div class="icon-circle icon-purple"><el-icon><RefreshRight /></el-icon></div>
                      <span class="badge badge-purple">Quarterly Full Refresh</span>
                      <span class="sub">季度复核</span>
                    </div>
                    <ul class="card-list">
                      <li><label>内容</label><span>净值、财务指标、货基收益、融资融券</span></li>
                      <li><label>频率</label><span>季末（推荐）</span></li>
                      <li><label>方式</label><span>覆盖式更新月初至今</span></li>
                      <li><label>适用</label><span>季度对账、漏采修补、确保数据完整</span></li>
                    </ul>
                    <details class="card-actions">
                      <summary>展开更多说明</summary>
                      <div class="card-more">
                        建议：季末进行一次全量复核；运行时间可选在业务低峰，避免与日常任务冲突。
                      </div>
                    </details>
                  </div>
                </div>

                <el-alert type="info" :closable="false" show-icon class="overview-tip">
                  <template #title>
                    所有计划在实际执行时，时间窗口都会自动裁剪到“账号可访问的最近 15 个月 ~ 3 个月”范围内，避免越权请求。
                  </template>
                </el-alert>
              </div>
              <div class="cfg-sample">
                <div>若需修改自动更新周期，请联系系统管理员在application.properties覆盖：</div>
                <pre class="cfg-pre">fund.scheduler.enabled=true
fund.scheduler.username=xxx
fund.scheduler.password=xxx
fund.scheduler.fundCodes=000001.OF,159915.XSHE
fund.scheduler.daily.cron=0 0 3 * * ?</pre>
              </div>
              <div class="auto-actions">
                <el-input v-model="presetForm.fundCodesRaw" placeholder="可选：限制触发的基金列表(逗号/换行)" />
                <el-button type="primary" @click="triggerDaily" :loading="running">立即执行 daily-market 计划</el-button>
              </div>
            </div>
          </div>
        </el-tab-pane>
      </el-tabs>

      <div class="result-wrap">
        <div class="result-header">
          <span class="result-title">执行结果</span>
          <div class="ops">
            <el-button text type="danger" @click="clearLogs">清空日志</el-button>
          </div>
        </div>

        <div class="progress-line" v-if="running || lastResult">
          <el-progress :percentage="displayedProgress" :indeterminate="isIndeterminate" :status="lastResult && lastResult.status==='success' ? 'success' : undefined" :text-inside="true" :stroke-width="18" style="max-width: 520px;"/>
        </div>

        <div v-if="lastResult">
          <!-- 如果有子结果，显示子结果列表 -->
          <div v-if="lastResult.subResults && lastResult.subResults.length > 1" class="sub-results">
            <h4>更新任务详情</h4>
            <el-card v-for="(subResult, idx) in lastResult.subResults" :key="idx" class="sub-result-card" :class="subResult.status === 'success' ? 'success' : 'fail'">
              <div class="sub-result-header">
                <el-tag :type="subResult.status==='success' ? 'success' : 'danger'" size="small">{{ subResult.type }}</el-tag>
                <el-tag :type="subResult.status==='success' ? 'success' : 'danger'" size="small">{{ subResult.status==='success' ? '成功' : '失败' }}</el-tag>
              </div>
              <div class="sub-result-message">{{ subResult.message || '无信息' }}</div>
              <div v-if="subResult.stats && Object.keys(subResult.stats).length" class="sub-result-stats">
                <span v-for="(count, statType) in subResult.stats" :key="statType" class="stat-item">
                  <b>{{ statType }}:</b> {{ count }}
                </span>
              </div>
            </el-card>
          </div>
          
          <div class="status-line">
            <el-tag :type="lastResult.status==='success' ? 'success' : 'danger'">{{ lastResult.status==='success' ? '成功' : '失败' }}</el-tag>
            <span class="msg">{{ lastResult.message }}</span>
          </div>
          <div class="nums">
            <el-statistic :value="lastResult.totalFunds || 0" title="基金数"/>
            <el-statistic :value="lastResult.totalTypes || 0" title="类型数"/>
            <el-statistic :value="lastResult.successCount || 0" title="成功数"/>
            <el-statistic :value="lastResult.failureCount || 0" title="失败数"/>
            <el-statistic :value="lastResult.totalSaved || 0" title="已保存"/>
            <el-statistic :value="lastResult.totalSkipped || 0" title="已跳过"/>
          </div>

          <div class="stats-table" v-if="lastResult.stats && Object.keys(lastResult.stats).length">
            <h4>数据类型统计</h4>
            <el-table :data="statsToRows(lastResult.stats)" border stripe style="max-width: 680px;">
              <el-table-column prop="type" label="数据类型" width="260"/>
              <el-table-column prop="count" label="保存数量"/>
            </el-table>
          </div>

          <div class="preview" v-if="lastResult.preview && Object.keys(lastResult.preview).length">
            <h4>数据预览</h4>
            <el-tabs type="border-card">
              <el-tab-pane v-for="(items, dtype) in lastResult.preview" :key="dtype" :label="dtype">
                <el-table :data="Array.isArray(items) ? items.slice(0,3) : []" border stripe>
                  <el-table-column v-for="col in Object.keys(Array.isArray(items) && items[0] ? items[0] : {})" :key="col" :prop="col" :label="col" min-width="120"/>
                </el-table>
              </el-tab-pane>
            </el-tabs>
          </div>
        </div>

        <el-empty v-else description="暂无执行记录"></el-empty>

        <div class="history" v-if="logs.length">
          <h4>历史记录（最近 {{ logs.length }} 次）</h4>
          <el-timeline>
            <el-timeline-item v-for="(log, idx) in logs" :key="idx" :type="log.status==='success' ? 'success' : 'danger'" :timestamp="formatTime(log.time)">
              {{ log.message }}
            </el-timeline-item>
          </el-timeline>
        </div>
      </div>
    </el-card>
    </div>
    <!-- 问答机器人 -->
    <QABot />
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
import { ElMessage } from 'element-plus';
import { DataAnalysis, User, Lock, Check, TrendCharts, Histogram, Document, RefreshRight, InfoFilled, FullScreen, Clock, Warning, Delete } from '@element-plus/icons-vue';
import { executeBatchCollection, executePlan, triggerAnnouncementUpdate, triggerHoldingUpdate } from '@/api/collectionApi';
import QABot from '@/components/QABot.vue';

const STORAGE_ACCOUNT = 'fund_data_hub_account_v1';
const STORAGE_LOGS = 'fund_data_hub_logs_v1';

const activeTab = ref('preset');
const running = ref(false);

const account = ref({ username: '', password: '' });
const remember = ref(true);

function loadAccount() {
  try {
    const raw = localStorage.getItem(STORAGE_ACCOUNT);
    if (raw) {
      const obj = JSON.parse(raw);
      account.value.username = obj.username || '';
      account.value.password = obj.password || '';
      remember.value = true;
    }
  } catch {}
}

function saveAccountIfNeeded() {
  if (remember.value) {
    localStorage.setItem(STORAGE_ACCOUNT, JSON.stringify({ username: account.value.username, password: account.value.password }));
    ElMessage.success('账号已保存');
  } else {
    localStorage.removeItem(STORAGE_ACCOUNT);
    ElMessage.success('已清除保存的账号');
  }
}

onMounted(() => loadAccount());

const DATA_TYPE_OPTS = [
  { label: '基金净值', value: 'FUND_NET_VALUE' },
  { label: '基金扩展信息', value: 'FUND_EXTRAS' },
  { label: '基金财务指标', value: 'FUND_FIN_INDICATOR' },
  { label: '分红送配', value: 'FUND_DIVIDEND' },
  { label: '货基每日收益', value: 'FUND_MF_DAILY_PROFIT' },
  { label: '融资融券（MTSS）', value: 'FUND_MTSS' },
];

// --- Advanced Form ---
const dateRange = ref([]); // [start, end]
const advancedForm = ref({
  fundCodesRaw: '',
  dataTypes: [],
  mode: 'AUTO_UPDATE',
  strategy: 'INCREMENTAL',
  recentDays: 7,
  concurrent: true,
  deleteOldBeforeInsert: false,
});

// --- Announcement and Holding Form ---
const announcementHoldingForm = ref({
  enableAnnouncement: false,
  announcementMode: 'full',
  enableHolding: false,
  holdingMode: 'quarterly',
  holdingYear: new Date().getFullYear(),
});

// 公告更新模式选项
const announcementModes = [
  { 
    value: 'full', 
    label: '全量更新', 
    desc: '更新所有公告数据',
    icon: 'FullScreen'
  },
  { 
    value: 'quarterly', 
    label: '季度更新', 
    desc: '更新本季度公告',
    icon: 'Clock'
  },
  { 
    value: 'semi-annual', 
    label: '半年度更新', 
    desc: '更新本半年度公告',
    icon: 'Clock'
  },
  { 
    value: 'important-events', 
    label: '重大事件更新', 
    desc: '仅更新重大事件公告',
    icon: 'Warning'
  },
  { 
    value: 'cleanup', 
    label: '清理旧数据', 
    desc: '清理过期公告数据',
    icon: 'Delete'
  },
];

// 持仓更新模式选项
const holdingModes = [
  { 
    value: 'year', 
    label: '更新指定年份', 
    desc: '更新指定年份的持仓数据',
    icon: 'Clock'
  },
  { 
    value: 'quarterly', 
    label: '季度更新', 
    desc: '更新本季度持仓',
    icon: 'Clock'
  },
  { 
    value: 'semi-annual', 
    label: '半年度更新', 
    desc: '更新本半年度持仓',
    icon: 'Clock'
  },
  { 
    value: 'annual', 
    label: '年度更新', 
    desc: '更新本年度持仓',
    icon: 'Clock'
  },
  { 
    value: 'cleanup', 
    label: '清理旧数据', 
    desc: '清理过期持仓数据',
    icon: 'Delete'
  },
];

function parseFundCodes(raw) {
  if (!raw) return [];
  return raw
    .split(/[,\n\r\t]/)
    .map(s => s.trim())
    .filter(Boolean);
}

function buildDateRange() {
  if (advancedForm.value.strategy === 'RECENT_DAYS') {
    return { startDate: null, endDate: null, recentDays: advancedForm.value.recentDays };
  }
  const [start, end] = dateRange.value || [];
  return {
    startDate: start ? formatDate(start) : null,
    endDate: end ? formatDate(end) : null,
    recentDays: null,
  };
}

function formatDate(d) {
  if (!d) return null;
  const date = new Date(d);
  const y = date.getFullYear();
  const m = String(date.getMonth() + 1).padStart(2, '0');
  const dd = String(date.getDate()).padStart(2, '0');
  return `${y}-${m}-${dd}`;
}

function resetAdvanced() {
  advancedForm.value = { fundCodesRaw: '', dataTypes: [], mode: 'AUTO_UPDATE', strategy: 'INCREMENTAL', recentDays: 7, concurrent: true, deleteOldBeforeInsert: false };
  dateRange.value = [];
}

function resetAnnouncementHolding() {
  announcementHoldingForm.value = {
    enableAnnouncement: false,
    announcementMode: 'full',
    enableHolding: false,
    holdingMode: 'quarterly',
    holdingYear: new Date().getFullYear(),
  };
}

async function runAdvanced() {
  if (!account.value.username || !account.value.password) {
    ElMessage.warning('请先填写账号与密码');
    return;
  }
  if (!advancedForm.value.dataTypes.length) {
    ElMessage.warning('请至少选择一个数据类型');
    return;
  }
  running.value = true;
  try {
    const payload = {
      username: account.value.username,
      password: account.value.password,
      fundCodes: parseFundCodes(advancedForm.value.fundCodesRaw),
      dataTypes: advancedForm.value.dataTypes,
      mode: advancedForm.value.mode,
      strategy: advancedForm.value.strategy,
      dateRange: buildDateRange(),
      concurrent: !!advancedForm.value.concurrent,
      deleteOldBeforeInsert: advancedForm.value.deleteOldBeforeInsert ? true : null,
    };
    const resp = await executeBatchCollection(payload);
    handleResult(resp?.data);
    ElMessage.success('自定义更新已提交');
  } catch (e) {
    handleResult({ status: 'fail', message: e?.response?.data?.message || e.message || '请求失败' });
  } finally {
    running.value = false;
  }
}

async function runAnnouncementHolding() {
  if (!account.value.username || !account.value.password) {
    ElMessage.warning('请先填写账号与密码');
    return;
  }
  
  const hasAnnouncementUpdate = announcementHoldingForm.value.enableAnnouncement;
  const hasHoldingUpdate = announcementHoldingForm.value.enableHolding;
  
  if (!hasAnnouncementUpdate && !hasHoldingUpdate) {
    ElMessage.warning('请至少选择一种更新类型（公告或持仓）');
    return;
  }
  
  running.value = true;
  const allResults = [];
  
  try {
    // 1. 执行公告更新（如果启用）
    if (hasAnnouncementUpdate) {
      try {
        const mode = announcementHoldingForm.value.announcementMode;
        const resp = await triggerAnnouncementUpdate(mode);
        if (resp?.data) {
          allResults.push({ type: '基金公告', ...resp.data });
        }
        ElMessage.success('基金公告更新已提交');
      } catch (e) {
        allResults.push({ 
          type: '基金公告', 
          status: 'fail', 
          message: e?.response?.data?.message || e.message || '基金公告更新请求失败' 
        });
      }
    }
    
    // 2. 执行持仓更新（如果启用）
    if (hasHoldingUpdate) {
      try {
        let mode = announcementHoldingForm.value.holdingMode;
        let apiPath = mode;
        // 如果是年份模式，需要构建带年份的URL
        if (mode === 'year') {
          const year = announcementHoldingForm.value.holdingYear || new Date().getFullYear();
          apiPath = `year/${year}`;
        }
        const resp = await triggerHoldingUpdate(apiPath);
        if (resp?.data) {
          allResults.push({ type: '基金持仓', ...resp.data });
        }
        ElMessage.success('基金持仓更新已提交');
      } catch (e) {
        allResults.push({ 
          type: '基金持仓', 
          status: 'fail', 
          message: e?.response?.data?.message || e.message || '基金持仓更新请求失败' 
        });
      }
    }
    
    // 处理结果
    if (allResults.length > 0) {
      // 如果只有一个结果，直接使用；否则合并
      if (allResults.length === 1) {
        handleResult(allResults[0]);
      } else {
        const mergedResult = mergeResults(allResults);
        handleResult(mergedResult);
      }
    }
    
  } catch (e) {
    handleResult({ status: 'fail', message: e?.response?.data?.message || e.message || '请求失败' });
  } finally {
    running.value = false;
  }
}

// 合并多个更新结果
function mergeResults(results) {
  const merged = {
    status: 'success',
    message: '',
    progress: 0,
    preview: {},
    stats: {},
    totalFunds: 0,
    totalTypes: 0,
    successCount: 0,
    failureCount: 0,
    totalSaved: 0,
    totalSkipped: 0,
    subResults: results, // 保存子结果用于显示
  };
  
  let totalProgress = 0;
  let successCount = 0;
  let failCount = 0;
  
  results.forEach(result => {
    if (result.status === 'fail') {
      merged.status = 'fail';
      failCount++;
    } else {
      successCount++;
    }
    
    totalProgress += result.progress || 0;
    
    // 合并统计数据
    if (result.stats) {
      Object.assign(merged.stats, result.stats);
    }
    
    // 合并预览数据
    if (result.preview) {
      if (Array.isArray(result.preview)) {
        merged.preview[result.type] = result.preview;
      } else if (typeof result.preview === 'object') {
        Object.assign(merged.preview, result.preview);
      }
    }
    
    merged.totalFunds += result.totalFunds || 0;
    merged.totalTypes += result.totalTypes || 0;
    merged.successCount += result.successCount || 0;
    merged.failureCount += result.failureCount || 0;
    merged.totalSaved += result.totalSaved || 0;
    merged.totalSkipped += result.totalSkipped || 0;
  });
  
  merged.progress = Math.round(totalProgress / results.length);
  merged.message = `共执行 ${results.length} 项更新：${successCount} 项成功，${failCount} 项失败`;
  
  return merged;
}

// --- Preset Plans ---
const plans = ref([
  { planCode: 'daily-market', brief: '每日行情维护', dataTypes: ['NET_VALUE','MF_DAILY_PROFIT','MTSS'], mode: 'AUTO_UPDATE', strategy: 'INCREMENTAL', window: '最近7天', tip: '每天盘后跑一次，保持行情数据最新。' },
  { planCode: 'weekly-leverage', brief: '周度杠杆资金', dataTypes: ['MTSS'], mode: 'AUTO_UPDATE', strategy: 'INCREMENTAL', window: '最近14天', tip: '每周补一次杠杆数据，便于做周度对比。' },
  { planCode: 'monthly-financial', brief: '月度财报指标', dataTypes: ['FIN_INDICATOR'], mode: 'MANUAL_UPDATE', strategy: 'INCREMENTAL', window: '最近一季度', tip: '月初拉财务指标，补齐最新季报/半年报。' },
  { planCode: 'quarterly-full-refresh', brief: '季度全量复核', dataTypes: ['NET_VALUE','FIN_INDICATOR','MF_DAILY_PROFIT','MTSS'], mode: 'MANUAL_UPDATE', strategy: 'FULL_RANGE', window: '月初至今', tip: '季末全量复核，防止漏采。' },
]);

const selectedPlan = ref(null);
const presetForm = ref({ fundCodesRaw: '' });

async function runPlan() {
  if (!account.value.username || !account.value.password) {
    ElMessage.warning('请先填写账号与密码');
    return;
  }
  if (!selectedPlan.value) {
    ElMessage.warning('请先选择一个计划');
    return;
  }
  running.value = true;
  try {
    const payload = {
      username: account.value.username,
      password: account.value.password,
      fundCodes: parseFundCodes(presetForm.value.fundCodesRaw),
    };
    const resp = await executePlan(selectedPlan.value.planCode, payload);
    handleResult(resp?.data);
    ElMessage.success('预设计划已提交');
  } catch (e) {
    handleResult({ status: 'fail', message: e?.response?.data?.message || e.message || '请求失败' });
  } finally {
    running.value = false;
  }
}

async function triggerDaily() {
  selectedPlan.value = plans.value.find(p => p.planCode === 'daily-market') || null;
  await runPlan();
}

// --- Scheduler status ---
const scheduler = ref({ enabled: false, username: '', fundCodes: [] });
async function refreshScheduler() {
  try {
    //const resp = await getSchedulerStatus();
    const data = resp?.data || {};
    scheduler.value = {
      enabled: !!data.enabled,
      username: data.username || '',
      fundCodes: Array.isArray(data.fundCodes) ? data.fundCodes : parseFundCodes(data.fundCodes || ''),
    };
  } catch {
    // 后端可能未实现该接口，保持静默
  }
}

onMounted(() => refreshScheduler());

// --- UI State (display only) ---
const compactMode = ref(false);

// --- Labels for display ---
const modeLabel = { AUTO_UPDATE: '自动更新', MANUAL_UPDATE: '手动更新' };
const strategyLabel = { INCREMENTAL: '增量', FULL_RANGE: '全量区间', RECENT_DAYS: '最近天数' };
function mapPlanTypes(arr) {
  const dict = { NET_VALUE: '净值', MF_DAILY_PROFIT: '货基每日收益', MTSS: '融资融券', FIN_INDICATOR: '财务指标' };
  return (arr || []).map(t => dict[t] || t).join(' / ');
}

// --- Progress display ---
const displayedProgress = computed(() => {
  const p = lastResult.value?.progress;
  if (running.value && (p == null || p === 0)) return 30; // 请求中但无进度时给出占位进度
  return p || 0;
});
const isIndeterminate = computed(() => running.value && (!lastResult.value || !lastResult.value.progress));

// --- Shared Result Area & Logs ---
const logs = ref([]); // [{time, status, message, raw}]
const lastResult = computed(() => logs.value.length ? logs.value[0].raw : null);

function loadLogs() {
  try {
    const arr = JSON.parse(localStorage.getItem(STORAGE_LOGS) || '[]');
    logs.value = arr;
  } catch {
    logs.value = [];
  }
}

function saveLogs() {
  localStorage.setItem(STORAGE_LOGS, JSON.stringify(logs.value.slice(0, 10)));
}

function handleResult(raw) {
  const record = { time: Date.now(), status: raw?.status || 'fail', message: raw?.message || '无信息', raw };
  logs.value = [record, ...logs.value].slice(0, 10);
  saveLogs();
}

function clearLogs() {
  logs.value = [];
  saveLogs();
}

function statsToRows(stats) {
  return Object.entries(stats || {}).map(([type, count]) => ({ type, count }));
}

function formatTime(ts) {
  const d = new Date(ts);
  const y = d.getFullYear();
  const m = String(d.getMonth()+1).padStart(2,'0');
  const day = String(d.getDate()).padStart(2,'0');
  const hh = String(d.getHours()).padStart(2,'0');
  const mm = String(d.getMinutes()).padStart(2,'0');
  const ss = String(d.getSeconds()).padStart(2,'0');
  return `${y}-${m}-${day} ${hh}:${mm}:${ss}`;
}

onMounted(() => loadLogs());
</script>

<style scoped>
/* ========== 包装器 ========== */
.fund-data-hub-wrapper {
  width: 100%;
  overflow-x: hidden;
  overflow-y: auto;
  height: 100vh;
}

/* ========== 全局容器 ========== */
.fund-data-hub {
  min-height: 100vh;
  padding: 20px; /* 减少内边距，使页面不那么长 */
  background: linear-gradient(135deg, #e3f2fd 0%, #f0f9ff 25%, #ffffff 60%, #fafcff 100%);
  animation: gradientShift 15s ease infinite;
  position: relative;
  overflow-x: hidden;
  transform: scale(0.85);
  transform-origin: top center;
  width: 117.65%; /* 100% / 0.85 以保持原始宽度 */
  margin-left: -8.825%; /* 居中调整 */
  margin-bottom: calc(-15vh * 0.85); /* 补偿缩放后的高度，减少底部空白 */
  padding-bottom: calc(20px / 0.85); /* 调整底部内边距 */
  box-sizing: border-box;
}

.fund-data-hub::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: 
    radial-gradient(circle at 20% 30%, rgba(64, 158, 255, 0.08) 0%, transparent 50%),
    radial-gradient(circle at 80% 70%, rgba(102, 126, 234, 0.06) 0%, transparent 50%);
  pointer-events: none;
  z-index: 0;
}

@keyframes gradientShift {
  0%, 100% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
}

/* ========== 头部卡片 ========== */
.header-card {
  border: none;
  border-radius: 20px;
  background: linear-gradient(135deg, #ffffff 0%, #f8fbff 100%);
  margin-bottom: 20px; /* 减少间距 */
  box-shadow: 
    0 20px 60px rgba(64, 158, 255, 0.15),
    0 8px 24px rgba(0, 0, 0, 0.08),
    0 0 0 1px rgba(64, 158, 255, 0.1);
  overflow: hidden;
  transition: all 0.3s ease;
  position: relative;
  z-index: 1;
}

.header-card > * {
  position: relative;
  z-index: 1;
}

.header-card:hover {
  box-shadow: 
    0 24px 72px rgba(64, 158, 255, 0.18),
    0 12px 32px rgba(0, 0, 0, 0.1),
    0 0 0 1px rgba(64, 158, 255, 0.15);
  transform: translateY(-2px);
}

.title {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 22px 28px;
  background: linear-gradient(135deg, rgba(15, 95, 255, 0.62) 0%, rgba(87, 184, 245, 0.97) 45%, rgba(168, 237, 234, 0.87) 100%);
  color: rgba(255, 255, 255, 0.98);
  position: relative;
  overflow: hidden;
}

/* 增强渐变层次的高光与暗角 */
.title::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(1200px 200px at -10% -50%, rgba(255,255,255,0.28), rgba(255,255,255,0) 60%),
              radial-gradient(800px 200px at 110% 150%, rgba(0,0,0,0.12), rgba(0,0,0,0) 60%);
  pointer-events: none;
}

/* 顶部微光条，增强层次感 */
.title::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  background: linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,0.75), rgba(255,255,255,0));
  opacity: 0.9;
}

.title-icon {
  font-size: 28px;
  animation: pulse 2s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.05); }
}

.title-text {
  font-size: 24px;
  font-weight: 700;
  letter-spacing: 0.5px;
}

.title-divider {
  font-size: 20px;
  opacity: 0.7;
  margin: 0 4px;
}

.title-subtitle {
  font-size: 16px;
  font-weight: 400;
  opacity: 0.95;
}

.account-bar {
  padding: 16px 20px; /* 减少内边距 */
  background: linear-gradient(to bottom, #fafcff, #ffffff);
}

.account-form {
  margin-bottom: 16px;
}

.account-form :deep(.el-input) {
  width: 220px;
}

.account-form :deep(.el-button) {
  padding: 8px 24px;
  font-weight: 500;
  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.2);
  transition: all 0.3s ease;
}

.account-form :deep(.el-button:hover) {
  box-shadow: 0 4px 16px rgba(64, 158, 255, 0.3);
  transform: translateY(-1px);
}

.tips {
  font-size: 13px;
  line-height: 1.6;
}

.account-alert {
  margin-top: 16px;
  border-radius: 12px;
  border: 1px solid rgba(64, 158, 255, 0.2);
  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.08);
}

.account-tip-card {
  margin-top: 16px;
  padding: 20px 24px;
  background: linear-gradient(135deg, #f8fbff 0%, #ffffff 100%);
  border: 1px solid rgba(64, 158, 255, 0.15);
  border-left: 4px solid #409EFF;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.1);
  display: flex;
  gap: 16px;
  transition: all 0.3s ease;
}

.account-tip-card:hover {
  box-shadow: 0 6px 16px rgba(64, 158, 255, 0.15);
  transform: translateX(4px);
}

.tip-icon-account {
  font-size: 24px;
  color: #409EFF;
  flex-shrink: 0;
  margin-top: 2px;
}

.tip-content-account {
  flex: 1;
}

.tip-title-account {
  font-size: 16px;
  font-weight: 600;
  color: #303133;
  margin-bottom: 12px;
}

.tip-list-account {
  margin: 0;
  padding-left: 20px;
  list-style: none;
}

.tip-list-account li {
  font-size: 14px;
  color: #606266;
  line-height: 1.8;
  margin-bottom: 8px;
  position: relative;
  padding-left: 12px;
}

.tip-list-account li::before {
  content: '•';
  position: absolute;
  left: 0;
  color: #409EFF;
  font-weight: bold;
}

.tip-list-account li:last-child {
  margin-bottom: 0;
}

/* ========== 主卡片 ========== */
.main-card {
  border: none;
  border-radius: 20px;
  background: linear-gradient(135deg, #ffffff 0%, #f8fcff 100%);
  box-shadow: 
    0 20px 60px rgba(64, 158, 255, 0.15),
    0 8px 24px rgba(0, 0, 0, 0.08),
    0 0 0 1px rgba(64, 158, 255, 0.1);
  overflow: hidden;
  position: relative;
  z-index: 1;
  transition: all 0.3s ease;
}

.main-card > * {
  position: relative;
  z-index: 1;
}

.main-card:hover {
  box-shadow: 
    0 24px 72px rgba(64, 158, 255, 0.18),
    0 12px 32px rgba(0, 0, 0, 0.1),
    0 0 0 1px rgba(64, 158, 255, 0.15);
}

.main-card :deep(.el-tabs__header) {
  margin: 0;
  padding: 0 24px;
  background: linear-gradient(to right, #f5faff, #ffffff);
  border-bottom: 2px solid #e8f4ff;
}

.main-card :deep(.el-tabs__item) {
  font-size: 15px;
  font-weight: 500;
  padding: 0 24px;
  height: 48px;
  line-height: 48px;
  transition: all 0.3s ease;
}

.main-card :deep(.el-tabs__item:hover) {
  color: rgba(64, 158, 255, 0.91);
}

.main-card :deep(.el-tabs__item.is-active) {
  color: #409EFF;
  font-weight: 600;
}

/* ========== Tab内容区 ========== */
.tab-wrap {
  padding: 24px 20px; /* 减少内边距 */
  display: flex;
  flex-direction: column;
  gap: 20px;
  align-items: center;
  justify-content: center;
}

.form-cards-container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  max-width: 1600px;
  margin: 0 auto;
}

.form-card {
  border-radius: 12px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.03);
  border: 1px solid #dce9ff;
  transition: all 0.3s ease;
}

.form-card:hover {
  box-shadow: 0 4px 20px rgba(64, 158, 255, 0.15);
  transform: translateY(-2px);
}

.form-card :deep(.el-card__header) {
  background: linear-gradient(135deg, #f5faff 0%, #ffffff 100%);
  border-bottom: 2px solid #e8f4ff;
  padding: 16px 20px;
}

.card-header {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 16px;
  font-weight: 600;
  color: #303133;
}

.card-header .el-icon {
  font-size: 20px;
  color: #409EFF;
}

.left-card {
  background: linear-gradient(135deg, #fafcff 0%, #ffffff 100%);
}

.right-card {
  background: linear-gradient(135deg, #fff9f5 0%, #ffffff 100%);
}

.announcement-holding-container {
  padding: 16px 20px;
}

.update-section {
  margin-bottom: 16px;
  padding: 16px 20px;
  background: linear-gradient(135deg, #fafcff 0%, #ffffff 100%);
  border-radius: 12px;
  border: 1px solid #e8f4ff;
  transition: all 0.3s ease;
}

.update-section:hover {
  border-color: #c6e2ff;
  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.1);
}

.update-section:last-child {
  margin-bottom: 0;
}

.announcement-section {
  border-left: 4px solid #409EFF;
}

.holding-section {
  border-left: 4px solid #67c23a;
}

.section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
  padding-bottom: 12px;
  border-bottom: 2px solid #f0f9ff;
}

.section-title {
  display: flex;
  align-items: center;
  gap: 8px;
}

.section-icon {
  font-size: 20px;
  color: #409EFF;
}

.announcement-section .section-icon {
  color: #409EFF;
}

.holding-section .section-icon {
  color: #67c23a;
}

.section-name {
  font-size: 16px;
  font-weight: 600;
  color: #303133;
}

.section-content {
  margin-top: 16px;
}

.mode-selector {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
}

.mode-option {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 18px 14px;
  background: linear-gradient(135deg, #ffffff 0%, #f8fbff 100%);
  border: 2px solid #e8f4ff;
  border-radius: 12px;
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  overflow: hidden;
  min-height: 120px;
  justify-content: center;
}

.mode-option::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: linear-gradient(90deg, #409EFF, #66b1ff);
  transform: scaleX(0);
  transition: transform 0.3s ease;
}

.mode-option:hover {
  border-color: #c6e2ff;
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(64, 158, 255, 0.15);
}

.mode-option:hover::before {
  transform: scaleX(1);
}

.mode-option.active {
  border-color: #409EFF;
  background: linear-gradient(135deg, #e3f2fd 0%, #f0f9ff 100%);
  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.2);
}

.mode-option.active::before {
  transform: scaleX(1);
}

.mode-icon {
  font-size: 28px;
  color: #409EFF;
  margin-bottom: 10px;
  transition: all 0.3s ease;
  padding: 8px;
  background: linear-gradient(135deg, rgba(64, 158, 255, 0.1) 0%, rgba(102, 177, 255, 0.05) 100%);
  border-radius: 50%;
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.mode-option.active .mode-icon {
  color: #409EFF;
  transform: scale(1.1);
}

.holding-section .mode-icon {
  color: #67c23a;
  background: linear-gradient(135deg, rgba(103, 194, 58, 0.1) 0%, rgba(133, 215, 106, 0.05) 100%);
}

.holding-section .mode-option.active {
  border-color: #67c23a;
  background: linear-gradient(135deg, #f0f9ff 0%, #f5fdf0 100%);
}

.holding-section .mode-option.active .mode-icon {
  color: #67c23a;
  background: linear-gradient(135deg, rgba(103, 194, 58, 0.2) 0%, rgba(133, 215, 106, 0.1) 100%);
}

.holding-section .mode-option.active .mode-label {
  color: #67c23a;
}

.mode-label {
  font-size: 15px;
  font-weight: 600;
  color: #303133;
  margin-bottom: 6px;
  text-align: center;
  transition: color 0.3s ease;
}

.mode-option.active .mode-label {
  color: #409EFF;
}

.mode-desc {
  font-size: 12px;
  color: #909399;
  text-align: center;
  line-height: 1.5;
  transition: color 0.3s ease;
}

.mode-option.active .mode-desc {
  color: #606266;
}

.year-selector {
  margin-top: 16px;
  padding: 16px;
  background: linear-gradient(135deg, #fff9f0 0%, #ffffff 100%);
  border-radius: 8px;
  border: 1px solid #fde2c4;
}

.year-selector :deep(.el-form-item) {
  margin-bottom: 0;
}

.year-selector :deep(.el-form-item__label) {
  font-weight: 500;
  color: #303133;
}

.shared-actions {
  display: flex;
  justify-content: center;
  gap: 12px;
  padding: 16px 20px;
  background: linear-gradient(135deg, #f5f9ff 0%, #ffffff 100%);
  border-radius: 12px;
  border: 1px solid #e8f4ff;
  max-width: 100%;
  margin-top: 0;
}

.advanced-form {
  max-width: 1000px;
  width: 100%;
  padding: 24px;
  background: linear-gradient(135deg, #fafcff 0%, #ffffff 100%);
  border-radius: 12px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.03);
  border: 1px solid #dce9ff;
  margin: 0 auto;
}

.advanced-form :deep(.el-form-item__label) {
  font-weight: 500;
  color: #303133;
}

.advanced-form :deep(.el-checkbox) {
  margin-right: 24px;
  margin-bottom: 12px;
  padding: 8px 16px;
  background: #f5f9ff;
  border-radius: 8px;
  transition: all 0.2s ease;
}

.advanced-form :deep(.el-checkbox:hover) {
  background: #e8f4ff;
  transform: translateX(2px);
}

.advanced-form :deep(.el-checkbox.is-checked) {
  background: linear-gradient(135deg, #e3f2fd 0%, #d1e8ff 100%);
}

.advanced-form :deep(.el-input__wrapper),
.advanced-form :deep(.el-textarea__inner) {
  border-radius: 8px;
  transition: all 0.3s ease;
}

.advanced-form :deep(.el-input__wrapper:hover),
.advanced-form :deep(.el-textarea__inner:hover) {
  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.1);
}

.advanced-form :deep(.el-button) {
  padding: 10px 28px;
  font-weight: 500;
  border-radius: 8px;
  transition: all 0.3s ease;
}

.advanced-form :deep(.el-button--primary) {
  background: linear-gradient(135deg, #409EFF 0%, #66b1ff 100%);
  border: none;
  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.25);
}

.advanced-form :deep(.el-button--primary:hover) {
  box-shadow: 0 6px 20px rgba(64, 158, 255, 0.35);
  transform: translateY(-2px);
}

/* 两列行内布局（表单项同一行显示） */
.form-inline-2 {
  display: flex;
  gap: 24px;
  align-items: center;
  flex-wrap: wrap;
}
.form-inline-2 :deep(.el-form-item) {
  margin-right: 0;
}

/* ========== 预设更新计划标签页 ========== */
.preset-tab-content {
  padding: 24px 20px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.plan-section {
  width: 100%;
  margin-bottom: 0;
}

.announcement-holding-section {
  width: 100%;
  margin-top: 0;
}

.section-title-main {
  font-size: 18px;
  font-weight: 600;
  color: #303133;
  margin-bottom: 12px;
  padding-bottom: 8px;
  border-bottom: 2px solid #e8f4ff;
  display: flex;
  align-items: center;
  gap: 8px;
}

.section-title-main::before {
  content: '';
  width: 4px;
  height: 20px;
  background: linear-gradient(135deg, #409EFF 0%, #66b1ff 100%);
  border-radius: 2px;
}

.announcement-holding-card {
  border-radius: 12px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.03);
  border: 1px solid #dce9ff;
  background: linear-gradient(135deg, #ffffff 0%, #f8fcff 100%);
  margin-bottom: 12px;
}

.announcement-holding-card :deep(.el-card__body) {
  padding: 0;
}

/* ========== 预设计划网格 ========== */
.plan-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(240px, 1fr));
  gap: 16px; /* 减少间距 */
  margin-bottom: 12px; /* 减少底部间距 */
  padding: 20px; /* 减少内边距 */
  max-width: 1480px;
  margin-left: auto;
  margin-right: auto;
  background: linear-gradient(135deg, #f6fbff 0%, #ffffff 100%);
  border: 1px solid #dce9ff;
  border-radius: 12px;
}

.plan-card {
  cursor: pointer;
  border-radius: 12px;
  padding: 20px;
  background: linear-gradient(135deg, #ffffff 0%, #f9fcff 100%);
  border: 2px solid #e8f4ff;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  overflow: hidden;
}

.plan-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: linear-gradient(90deg, #409EFF, #66b1ff);
  transform: scaleX(0);
  transition: transform 0.3s ease;
}

.plan-card:hover {
  border-color: #409EFF;
  box-shadow: 0 8px 24px rgba(64, 158, 255, 0.15);
  transform: translateY(-4px);
}

.plan-card:hover::before {
  transform: scaleX(1);
}

.plan-card.selected {
  border-color: #409EFF;
  background: linear-gradient(135deg, #e3f2fd 0%, #f0f9ff 100%);
  box-shadow: 0 8px 32px rgba(64, 158, 255, 0.2);
  transform: translateY(-4px);
}

.plan-card.selected::before {
  transform: scaleX(1);
}

.plan-title {
  display: flex;
  align-items: center;
  gap: 12px;
  font-weight: 600;
  margin-bottom: 16px;
  font-size: 16px;
}

.plan-name {
  color: #303133;
  flex: 1;
}

.plan-meta {
  color: #606266;
  font-size: 14px;
  line-height: 2;
}

.plan-meta > div {
  padding: 4px 0;
}

.plan-meta b {
  color: #409EFF;
  font-weight: 600;
  margin-right: 4px;
}

.plan-meta .hint {
  color: #909399;
  margin-top: 12px;
  padding: 12px;
  background: #f5f7fa;
  border-radius: 8px;
  border-left: 3px solid #409EFF;
  font-style: italic;
  line-height: 1.6;
}

.preset-form {
  max-width: 1000px;
  padding: 16px 24px;
  background: linear-gradient(135deg, #fafcff 0%, #ffffff 100%);
  border-radius: 12px;
  margin: 0 auto 0 auto;
}

.preset-tips {
  margin-left: 16px;
  color: #909399;
  font-size: 13px;
  line-height: 1.6;
  padding: 8px 16px;
  background: #f5f7fa;
  border-radius: 6px;
  border-left: 3px solid #409EFF;
}

/* ========== 自动调度 ========== */
.auto-wrap {
  padding: 24px 20px; /* 减少内边距 */
}

.auto-status {
  max-width: 1000px;
  margin-left: auto;
  margin-right: auto;
  padding: 24px;
  background: linear-gradient(135deg, #f6fbff 0%, #ffffff 100%);
  border: 1px solid #dce9ff;
  border-radius: 12px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.03);
}

.auto-status .line {
  margin: 16px 0;
  padding: 12px 0;
  font-size: 14px;
  line-height: 1.8;
}

.auto-status .line b {
  color: #409EFF;
  font-weight: 600;
  margin-right: 8px;
}

.cfg-sample {
  margin: 24px 0;
  padding: 20px;
  background: linear-gradient(135deg, #f0f9ff 0%, #e3f2fd 100%);
  border-radius: 12px;
  border: 1px solid #d1e8ff;
}

.cfg-sample > div {
  font-weight: 600;
  color: #303133;
  margin-bottom: 12px;
}

.cfg-pre {
  background: linear-gradient(135deg, #0d2d52 0%, #1a3a5c 100%);
  color: #c5e7ff;
  padding: 20px;
  border-radius: 10px;
  white-space: pre-wrap;
  font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
  font-size: 13px;
  line-height: 1.8;
  box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.auto-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 24px;
  padding-top: 24px;
  border-top: 2px dashed #e8f4ff;
}

.auto-actions :deep(.el-input) {
  flex: 1;
  min-width: 300px;
}

/* ===== 自动更新策略概览 美化 ===== */
.auto-overview {
  margin-top: 8px;
  padding: 16px;
  background: linear-gradient(135deg, #f6fbff 0%, #ffffff 100%);
  border-radius: 12px;
  border: 1px solid #e8f4ff;
}

.overview-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 12px;
}

.overview-header .header-left {
  display: flex;
  flex-direction: column;
}

.overview-header h3 {
  margin: 0;
  font-size: 18px;
  font-weight: 700;
  color: #1f2d3d;
}

.overview-header p {
  margin: 6px 0 0 0;
  color: #5a697e;
  font-size: 14px;
}

.overview-tools {
  display: flex;
  align-items: center;
}

.overview-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(360px, 1fr));
  align-items: stretch;
  gap: 16px 18px;
  margin-top: 12px;
}

.overview-card {
  display: flex;
  flex-direction: column;
  min-height: 240px;
  background: linear-gradient(135deg, #ffffff 0%, #f9fcff 100%);
  border: 1px solid #e8f4ff;
  border-radius: 12px;
  padding: 16px 16px 12px 16px;
  box-shadow: 0 2px 10px rgba(64,158,255,0.06);
  transition: all .25s ease;
}

.overview-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 8px 22px rgba(64,158,255,0.15);
  border-color: #d6ecff;
}

.card-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
  padding: 12px 14px;
  border-radius: 10px;
  color: #fff;
  box-shadow: inset 0 -1px 0 rgba(255,255,255,0.15);
}

/* 渐变头部配色 */
.head-blue { background: linear-gradient(135deg, #3f8cff 0%, #6bb5ff 100%); }
.head-green { background: linear-gradient(135deg, #58c13a 0%, #86db6d 100%); }
.head-orange { background: linear-gradient(135deg, #e49a2c 0%, #f4c067 100%); }
.head-purple { background: linear-gradient(135deg, #7d6cf0 0%, #b3a6ff 100%); }

/* 头部内部元素在渐变背景下的样式优化 */
.card-head .sub { color: rgba(255,255,255,0.95); font-weight: 600; }
.card-head .badge { background: rgba(255,255,255,0.18); border: 1px solid rgba(255,255,255,0.28); color: #fff; }
.card-head .icon-circle { background: rgba(255,255,255,0.25); color: #fff; box-shadow: none; }

.badge {
  display: inline-block;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.3px;
  color: #fff;
}
.badge-blue { background: linear-gradient(135deg, #409EFF, #66b1ff); }
.badge-green { background: linear-gradient(135deg, #67c23a, #85d76a); }
.badge-orange { background: linear-gradient(135deg, #e6a23c, #f3bf6b); }
.badge-purple { background: linear-gradient(135deg, #8e7cf6, #b7a9ff); }

.icon-circle {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  box-shadow: 0 2px 8px rgba(0,0,0,0.12);
}
.icon-blue { background: linear-gradient(135deg, #409EFF, #66b1ff); }
.icon-green { background: linear-gradient(135deg, #67c23a, #85d76a); }
.icon-orange { background: linear-gradient(135deg, #e6a23c, #f3bf6b); }
.icon-purple { background: linear-gradient(135deg, #8e7cf6, #b7a9ff); }

.sub {
  color: #5a697e;
  font-size: 13px;
}

.card-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  row-gap: 8px;
}

.card-list li {
  display: grid;
  grid-template-columns: 70px 1fr;
  align-items: center;
  column-gap: 10px;
}

.card-list label {
  color: #8a9bb2;
  font-weight: 600;
}

.card-list span { color: #2f3b52; }

.card-actions { margin-top: auto; }

.card-actions summary {
  list-style: none;
  color: #409EFF;
  cursor: pointer;
}

.card-actions summary::-webkit-details-marker { display: none; }

.card-actions summary:hover { text-decoration: underline; }

.card-more {
  margin-top: 10px;
  padding: 10px 12px;
  background: #f5f7fa;
  border-left: 3px solid #409EFF;
  border-radius: 6px;
  color: #5a697e;
  line-height: 1.6;
}

/* 紧凑模式 */
.auto-overview.compact { padding: 12px; }
.auto-overview.compact .overview-card { min-height: 200px; padding: 12px; }
.auto-overview.compact .card-list { row-gap: 6px; }
.auto-overview.compact .badge { padding: 3px 8px; font-size: 11px; }

.overview-tip { margin-top: 14px; }

/* ========== 执行结果区 ========== */
.result-wrap {
  margin-top: 24px; /* 减少顶部间距 */
  padding: 24px 20px; /* 减少内边距 */
  border-top: 3px solid #e8f4ff;
  background: linear-gradient(to bottom, #fafcff, #ffffff);
}

.result-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 24px;
  padding-bottom: 16px;
  border-bottom: 2px solid #f0f9ff;
}

.result-title {
  font-size: 18px;
  font-weight: 600;
  color: #303133;
  display: flex;
  align-items: center;
  gap: 8px;
}


.progress-line {
  margin: 20px 0;
  padding: 20px 24px;
  background: linear-gradient(135deg, #f5f9ff 0%, #ffffff 100%);
  border-radius: 12px;
  border: 1px solid rgba(64, 158, 255, 0.1);
  box-shadow: 
    0 4px 12px rgba(64, 158, 255, 0.1),
    0 2px 6px rgba(0, 0, 0, 0.04);
}

.status-line {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 20px 0;
  padding: 18px 24px;
  background: linear-gradient(135deg, #f5f9ff 0%, #ffffff 100%);
  border-radius: 12px;
  border-left: 4px solid rgba(64, 158, 255, 0.56);
  box-shadow: 
    0 4px 12px rgba(64, 158, 255, 0.1),
    0 2px 6px rgba(0, 0, 0, 0.04);
}

.msg {
  color: #606266;
  font-size: 15px;
  font-weight: 500;
  flex: 1;
}

.nums {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  margin: 24px 0;
  padding: 20px;
  background: linear-gradient(135deg, #f5f9ff 0%, #ffffff 100%);
  border-radius: 12px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.03);
}

.nums :deep(.el-statistic) {
  flex: 1;
  text-align: center;
}

.nums :deep(.el-statistic__head) {
  font-size: 14px;
  font-weight: 500;
  color: #909399;
}

.nums :deep(.el-statistic__content) {
  font-size: 32px;
  font-weight: 700;
  color: rgba(64, 158, 255, 0.66);
}

.stats-table {
  margin-top: 24px;
  padding: 20px;
  background: linear-gradient(135deg, #fafcff 0%, #ffffff 100%);
  border-radius: 12px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.03);
}

.stats-table h4 {
  margin: 0 0 16px 0;
  font-size: 16px;
  font-weight: 600;
  color: #303133;
  display: flex;
  align-items: center;
  gap: 8px;
}

.stats-table h4::before {
  content: '📈';
}

.stats-table :deep(.el-table) {
  border-radius: 8px;
  overflow: hidden;
}

.stats-table :deep(.el-table th) {
  background: linear-gradient(135deg, rgba(64, 158, 255, 0.63) 0%, rgba(102, 177, 255, 0.51) 100%);
  color: #ffffff;
  font-weight: 600;
}

.preview {
  margin-top: 24px;
  padding: 20px;
  background: linear-gradient(135deg, #fafcff 0%, #ffffff 100%);
  border-radius: 12px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.03);
}

.preview h4 {
  margin: 0 0 16px 0;
  font-size: 16px;
  font-weight: 600;
  color: #303133;
  display: flex;
  align-items: center;
  gap: 8px;
}

.preview h4::before {
  content: '👁️';
}

.preview :deep(.el-tabs--border-card) {
  border-radius: 8px;
  overflow: hidden;
  box-shadow: none;
  border: 1px solid #e8f4ff;
}

.preview :deep(.el-tabs__header) {
  background: linear-gradient(to right, #f5faff, #ffffff);
}

.history {
  margin-top: 32px;
  padding: 20px;
  background: linear-gradient(135deg, #fafcff 0%, #ffffff 100%);
  border-radius: 12px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.03);
}

.history h4 {
  margin: 0 0 16px 0;
  font-size: 16px;
  font-weight: 600;
  color: #303133;
  display: flex;
  align-items: center;
  gap: 8px;
}

.history h4::before {
  content: '📜';
}

.history :deep(.el-timeline-item__timestamp) {
  font-weight: 500;
  color: #606266;
}

/* ========== 子结果卡片 ========== */
.sub-results {
  margin-bottom: 24px;
  padding: 20px;
  background: linear-gradient(135deg, #fafcff 0%, #ffffff 100%);
  border-radius: 12px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.03);
}

.sub-results h4 {
  margin: 0 0 16px 0;
  font-size: 16px;
  font-weight: 600;
  color: #303133;
}

.sub-result-card {
  margin-bottom: 12px;
  border-radius: 8px;
  transition: all 0.3s ease;
}

.sub-result-card.success {
  border-left: 4px solid #67c23a;
  background: linear-gradient(135deg, #f0f9ff 0%, #ffffff 100%);
}

.sub-result-card.fail {
  border-left: 4px solid #f56c6c;
  background: linear-gradient(135deg, #fff5f5 0%, #ffffff 100%);
}

.sub-result-header {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-bottom: 8px;
}

.sub-result-message {
  color: #606266;
  font-size: 14px;
  margin-bottom: 8px;
}

.sub-result-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  font-size: 13px;
  color: #909399;
}

.sub-result-stats .stat-item {
  padding: 4px 8px;
  background: #f5f7fa;
  border-radius: 4px;
}

.sub-result-stats .stat-item b {
  color: #409EFF;
  margin-right: 4px;
}

/* ========== 响应式优化 ========== */
@media (max-width: 1200px) {
  .plan-grid {
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  }
}

@media (max-width: 1200px) {
  .form-cards-container {
    grid-template-columns: 1fr;
  }
  
  .mode-selector {
    grid-template-columns: 1fr;
  }
  
  .plan-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 768px) {
  .fund-data-hub {
    padding: 16px;
  }
  
  .title-text {
    font-size: 18px;
  }
  
  .title-subtitle {
    display: none;
  }
  
  .plan-grid {
    grid-template-columns: 1fr;
  }
  
  .form-cards-container {
    grid-template-columns: 1fr;
  }
  
  .nums {
    grid-template-columns: repeat(2, 1fr);
    gap: 16px;
  }
  
  .auto-actions {
    flex-direction: column;
  }
  
  .auto-actions :deep(.el-input) {
    min-width: auto;
  }
}

/* ========== 全局增强 ========== */
:deep(.el-card__body) {
  padding: 0;
}

:deep(.el-alert) {
  border-radius: 8px;
  border: none;
}

:deep(.el-tag) {
  padding: 4px 12px;
  border-radius: 6px;
  font-weight: 500;
  border: none;
}

:deep(.el-button.is-round) {
  padding: 8px 20px;
}

:deep(.el-empty) {
  padding: 60px 0;
}

:deep(.el-empty__description) {
  color: #909399;
  font-size: 14px;
}
</style>

